/***********************************************************************************
 * 文件名： mcu_rtc.c
 * 作者： 刘言
 * 版本： 1
 * 说明：
 * 		RTC驱动。
 * 修改记录：
 * 	2024/7/18: 初版。 刘言。
***********************************************************************************/
#include "HAL_USP_Config.h"
#include "py32f4xx.h"
#include "typedef.h"


static void SetAlarm();
#if(RTC_EN && RTC_CLK_SEL)
static void EnterConfigMode();
static void ExitConfigMode();
#endif



void Rtc_Init()
{
    u32 temp_reg;

    // RTC时钟源设置

    // 关闭备份域写保护
    if (HAL_IS_BIT_CLR(PWR->CR, PWR_CR_DBP))
    {
      SET_BIT(PWR->CR, PWR_CR_DBP);/* Enable write access to Backup domain */
      while (HAL_IS_BIT_CLR(PWR->CR, PWR_CR_DBP));/* Wait for Backup domain Write protection disable */
    }
    // 修改RTC时钟源和时钟使能
    temp_reg = RCC->BDCR;
    if (((temp_reg & RCC_BDCR_RTCSEL) != (RTC_CLK_SEL << 8)) || ((temp_reg & RCC_BDCR_RTCEN) != (RTC_EN << 15)))   // 需要修改RTC时钟源
    {
        temp_reg = (RCC->BDCR & ~(RCC_BDCR_RTCSEL | RCC_BDCR_RTCEN));/* Store the content of BDCR register before the reset of Backup Domain */
        /* 复位备份域 RTC Clock selection can be changed only if the Backup Domain is reset */
        __HAL_RCC_BACKUPRESET_FORCE();
        __HAL_RCC_BACKUPRESET_RELEASE();
        temp_reg |= (RTC_CLK_SEL << 8 | RTC_EN << 15);
        RCC->BDCR = temp_reg;
        /* Wait for LSERDY if LSE was enabled */
        if (HAL_IS_BIT_SET(temp_reg, RCC_BDCR_LSEON))while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET);
    }

    // RTC配置
#if(RTC_EN && RTC_CLK_SEL)
    // 清零 RSF
    CLEAR_BIT(RTC->CRL, RTC_FLAG_RSF);
    // 等待寄存器同步（ RSF 自动变成1）
    while ((RTC->CRL & RTC_FLAG_RSF) == (uint32_t)RESET);

    EnterConfigMode();

    /* Clear Flags Bits */
    CLEAR_BIT(RTC->CRL, (RTC_FLAG_OW | RTC_FLAG_ALRAF | RTC_FLAG_SEC));
    /* Configure the RTC_PRLH / RTC_PRLL */
    MODIFY_REG(RTC->PRLH, RTC_PRLH_PRL, (RTC_CLK_DIV >> 16U));
    MODIFY_REG(RTC->PRLL, RTC_PRLL_PRL, (RTC_CLK_DIV & RTC_PRLL_PRL));

    ExitConfigMode();

    RTC->CRH = RTC_INT_EN << 1;
#if RTC_INT_EN
    /* RTC Alarm Interrupt Configuration: EXTI configuration */
    __HAL_RTC_ALARM_EXTI_ENABLE_IT();
    __HAL_RTC_ALARM_EXTI_ENABLE_RISING_EDGE();
    SetAlarm(2);
#endif
#endif
}

void Rtc_evAlarm()
{
    SetAlarm(1);
    CLEAR_BIT(RTC->CRL, RTC_CRL_ALRF);
    // (RTC->CRL) = ~(RTC_FLAG_ALRAF);
    __HAL_RTC_ALARM_EXTI_CLEAR_FLAG();
}


/**
 * 设置闹钟寄存器
 * @param inc 计数寄存器基础上增加量
 */
static void SetAlarm(u32 inc)
{
    uint16_t high1 = 0U, high2 = 0U, low = 0U;
    uint32_t timecounter = 0U;
    u32 alarm_count;

    high1 = READ_REG(RTC->CNTH & RTC_CNTH_RTC_CNT);
    low   = READ_REG(RTC->CNTL & RTC_CNTL_RTC_CNT);
    high2 = READ_REG(RTC->CNTH & RTC_CNTH_RTC_CNT);

    if (high1 != high2)
    {
        /* In this case the counter roll over during reading of CNTL and CNTH registers,
        read again CNTL register then return the counter value */
        timecounter = (((uint32_t) high2 << 16U) | READ_REG(RTC->CNTL & RTC_CNTL_RTC_CNT));
    }
    else
    {
        /* No counter roll over during reading of CNTL and CNTH registers, counter
        value is equal to first value of CNTL and CNTH */
        timecounter = (((uint32_t) high1 << 16U) | low);
    }

    alarm_count = timecounter + inc;

    EnterConfigMode();
    /* Set RTC COUNTER MSB word */
    WRITE_REG(RTC->ALRH, (alarm_count >> 16U));
    /* Set RTC COUNTER LSB word */
    WRITE_REG(RTC->ALRL, (alarm_count & RTC_ALRL_RTC_ALR));

    ExitConfigMode();
}

#if(RTC_EN && RTC_CLK_SEL)

static void EnterConfigMode()
{
    // 等待上一次对 RTC 寄存器的写操作已经完成
    while ((RTC->CRL & RTC_CRL_RTOFF) == (uint32_t)RESET);
    // 进入配置模式，允许向 RTC_CNT、RTC_ALR 或 RTC_PRL 寄存器写入新值，数据将会被缓存，只有当此位在被置’1’，并重新由软件清’0’后，才会执行写操作。
    SET_BIT(RTC->CRL, RTC_CRL_CNF);
}

static void ExitConfigMode()
{
    // 退出配置模式（同时真实写入寄存器）
    CLEAR_BIT(RTC->CRL, RTC_CRL_CNF);
    // 等待上一次对 RTC 寄存器的写操作已经完成
    while ((RTC->CRL & RTC_CRL_RTOFF) == (uint32_t)RESET);
}   

#endif

